﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.server.types;
using l1cs.server.datatables;
using l1cs.server.model.Instance;
using l1cs.server.model.map;
using System.Threading;

namespace l1cs.server.model
{
    public class ElementalStoneGenerator
    {
        private static Logger _log = Logger.getLogger( typeof( ElementalStoneGenerator ).FullName );

        private const int ELVEN_FOREST_MAPID = 4;
        private const int INTERVAL = 3; // 設置間隔 秒
        private const int SLEEP_TIME = 300; // 設置終了後、再設置までのスリープ時間 秒
        private const int FIRST_X = 32911;
        private const int FIRST_Y = 32210;
        private const int LAST_X = 33141;
        private const int LAST_Y = 32500;
        private const int ELEMENTAL_STONE_ID = 40515; // 精霊の石

        private List<L1GroundInventory> _itemList = new List<L1GroundInventory>( Config.ELEMENTAL_STONE_AMOUNT );
        private Random _random = new Random();

        private static ElementalStoneGenerator _instance = null;

        private ElementalStoneGenerator() { }

        public static ElementalStoneGenerator getInstance()
        {
            if ( _instance == null )
            {
                _instance = new ElementalStoneGenerator();
            }
            return _instance;
        }

        private L1Object _dummy = new L1Object();

        /// <summary>
        /// 指定された位置に石を置けるかを返す。
        /// </summary>
        /// <param name="loc"></param>
        /// <returns></returns>
        private bool canPut( L1Location loc )
        {
            _dummy.setMap( loc.getMap() );
            _dummy.setX( loc.getX() );
            _dummy.setY( loc.getY() );

            // 可視範囲のプレイヤーチェック
            if ( L1World.getInstance().getVisiblePlayer( _dummy ).Count > 0 )
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 次の設置ポイントを決める。
        /// </summary>
        /// <returns></returns>
        private Point nextPoint()
        {
            int newX = _random.Next( LAST_X - FIRST_X ) + FIRST_X;
            int newY = _random.Next( LAST_Y - FIRST_Y ) + FIRST_Y;

            return new Point( newX, newY );
        }

        /// <summary>
        /// 拾われた石をリストから削除する。
        /// </summary>
        private void removeItemsPickedUp()
        {
            for ( int i = 0; i < _itemList.Count; i++ )
            {
                L1GroundInventory gInventory = _itemList[i];
                if ( !gInventory.checkItem( ELEMENTAL_STONE_ID ) )
                {
                    _itemList.Remove( gInventory );
                    i--;
                }
            }
        }

        /// <summary>
        /// 指定された位置へ石を置く。
        /// </summary>
        /// <param name="loc"></param>
        private void putElementalStone( L1Location loc )
        {
            L1GroundInventory gInventory = L1World.getInstance().getInventory( loc );

            L1ItemInstance item = ItemTable.getInstance().createItem( ELEMENTAL_STONE_ID );
            item.setEnchantLevel( 0 );
            item.setCount( 1 );
            gInventory.storeItem( item );
            _itemList.Add( gInventory );
        }

        public void threadSub( Object state )
        {
            L1Map map = L1WorldMap.getInstance().getMap( (short)ELVEN_FOREST_MAPID );
            while ( true )
            {
                removeItemsPickedUp();

                while ( _itemList.Count < Config.ELEMENTAL_STONE_AMOUNT )
                { // 減っている場合セット
                    L1Location loc = new L1Location( nextPoint(), map );

                    if ( !canPut( loc ) )
                    {
                        // XXX 設置範囲内全てにPCが居た場合無限ループになるが…
                        continue;
                    }

                    putElementalStone( loc );

                    Thread.Sleep( INTERVAL * 1000 ); // 一定時間毎に設置
                }
                Thread.Sleep( SLEEP_TIME * 1000 ); // maxまで設置終了後一定時間は再設置しない
            }
        }
    }
}